/**
 * @file app\tasks\daemon\daemon.c
 *
 * Copyright (C) 2023
 *
 * daemon.c is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @author HinsShum hinsshum@qq.com
 *
 * @encoding utf-8
 */

 /*---------- includes ----------*/
#include "lists.h"
#include "options.h"
#include "resources.h"
#include "soft_timer.h"
#include "storage.h"
#include "systicks.h"
#include "tasks.h"
#include "trace.h"
#include "uuid.h"
#include <stdlib.h>

/*---------- macro ----------*/
#define TAG "Daemon"

/*---------- type define ----------*/
typedef struct node* node_t;
struct node {
    struct list_head n;
    daemon_cb_t cb;
};

/*---------- variable prototype ----------*/
/*---------- function prototype ----------*/
/*---------- variable ----------*/
static LIST_HEAD(head);

/*---------- function ----------*/
static inline bool _search_pool(daemon_cb_t cb) {
    bool searched = false;
    node_t p = NULL;

    list_for_each_entry(p, struct node, &head, n) {
        if (p->cb == cb) {
            searched = true;
            break;
        }
    }

    return searched;
}

bool daemon_add(daemon_cb_t cb) {
    node_t p = NULL;
    bool err = false;

    do {
        if (_search_pool(cb)) {
            err = true;
            break;
        }
        if (!cb) {
            break;
        }
        p = __malloc(sizeof(*p));
        if (!p) {
            break;
        }
        p->cb = cb;
        __enter_critical();
        list_add_tail(&p->n, &head);
        __exit_critical();
        err = true;
    } while (0);

    return err;
}

void daemon_del(daemon_cb_t cb) {
    node_t p = NULL;

    list_for_each_entry(p, struct node, &head, n) {
        if (p->cb == cb) {
            __enter_critical();
            list_del(&p->n);
            __exit_critical();
            __free(p);
            break;
        }
    }
}

static void _polling(void) {
    node_t p = NULL;

    list_for_each_entry(p, struct node, &head, n) { p->cb(); }
}

static void __random_delay(void) {
    uint32_t delay = 0;

    srand(uuid_get());
    delay = rand() % 1000 + 1000;
    __delay_ms(delay);
    xlog_tag_info(TAG, "Random delay %dms\n", delay);
}
static void _init(void) {
    at5820_bsp_init();
    /* initialize all peripherals */
    resources_init();
    /* random delay */
    __random_delay();
    /* initialize soft timer */
    systicks_add(soft_timer_tick);
    daemon_add(soft_timer_poll);
    /* initialize trace */
    trace_init();
    storage_init();
    /* new other tasks */
    app_led_Lisi_poll();
    app_key_poll();
    mobus_init();

    /* say hi */
    xlog_tag_message(TAG, "Initialize successfully\n");
}

void daemon_polling(void) {
    _init();
    for (;;) {
        _polling();
    }
}
